/**
 * @module NGS.Customer
 * @description 客户对象
 * @author Lori
 */
"use strict";

/**
 * @class Customer
 * @description 客户类
 */
define(function() {

	const Customer = function(project, fields, dbPool) {
		this.isPropertyChange = false;
		this.originalValues = {};
		this.values = {};
		this.project = project;
		this.fields = fields;
		this.dbPool = dbPool || '';
	};

	Customer.encFields = ['TEL_1', 'TEL_2', 'FAX', 'MOBILE', 'OTHERS', 'ADDRESS', 'CLUB_ID', 'CUSTOMER_ID', 'ADDRESS2'];
	Customer.anonymousGuid = "1                                   ";

	Customer.prototype = {
		getAnonymousGuid : function() {
			return Customer.anonymousGuid;
		},

		save : function(successCallback, failCallback, alwaysCallback, isSync) {
			const c = this,
				proj = this.project,
				fields = proj.customerFieldsCache.fields;
			let	tempCustomerGuid = this.getProperty("customer_guid");
			if (!$F.isEmpty(tempCustomerGuid) && tempCustomerGuid.trim() === Customer.anonymousGuid.trim()) {
				var tempCustomerName = this.getProperty("customername");
				if (tempCustomerName !== "匿名客户" && tempCustomerName !== "anonymous") {
					this.setPropertyByName("customer_guid", null);
					tempCustomerGuid = null;
				} else {
					$F.alert("不能修改匿名客户");
					failCallback && failCallback();
					alwaysCallback && alwaysCallback();
					return;
				}
			}

			if ($F.isEmpty(tempCustomerGuid)) {
				tempCustomerGuid = Guid.raw();
				this.setPropertyByName("customer_guid", tempCustomerGuid);
				proj.changeCurrentCustomerProperty("customer_guid", tempCustomerGuid);
			}

			//脱敏字段处理
			const encFields = [], needDecryptFields = [], needDecryptValues = [], needEncryptValues = [];
			fields.forEach(function(field) {
				field = field.toUpperCase();
				if (proj.customerEncFieldsMasker && proj.customerEncFieldsMasker[field]) {
					let fieldVal = c.getProperty(field);
					//先判断format的值和老的是否一致，一致表示这个字段没改过，就不需要后面的解密再比较了
					if (c.getOriginalPropertyByName(field) === fieldVal) {
						return;
					}
					let originalVal = c.getOriginalPropertyByName(field + '_ENC');
					needDecryptValues.push(originalVal);
					needDecryptFields.push({
						f: field,
						v: fieldVal
					});
				}
			});
			//批量解密比较
			if (needDecryptValues.length > 0) {
				let decryptValues = $F.Security.dbMasker(needDecryptValues, true);
				decryptValues.forEach(function(decryptValue, i) {
					if (needDecryptFields[i].v !== decryptValue) {
						encFields.push(needDecryptFields[i].f);
						needEncryptValues.push(needDecryptFields[i].v);
					} else {
						c.setPropertyByName(needDecryptFields[i].f, c.getOriginalPropertyByName(needDecryptFields[i].f));
					}
				});
			}

			if (encFields.length > 0) {
				if (proj.isDbMask()) {
					//批量加密
					let encryptedValues = $F.Security.dbMasker(needEncryptValues);
					encFields.forEach(function(encField, i){
						var encFieldValue = c.getProperty(encField);
						var formatedValue = CtlUtils.expression(encFieldValue, proj.customerEncFieldsMasker[encField].FORMAT);
						c.setPropertyByName(encField, formatedValue);
						c.setPropertyByName(encField + '_ENC', encryptedValues[i]);
					});
					//修改了加密字段，需要界面刷新，显示新的format后的值
					proj.showCustomerDetail(encFields);
				} else {
					//如果不脱敏，_ENC字段直接存明文
					encFields.forEach(function(encField){
						c.setPropertyByName(encField + '_ENC', c.getProperty(encField));
					});
				}
			}

			const bd = new BoundData("Customer" + $E.staff.epidSql);
			bd.setKey('customer_guid');
			bd.setValue('customer_guid', tempCustomerGuid);
			bd.setCreateInfo("CREATEDDATE", "CREATEDBY", $E.staff.id);
			bd.setModifyInfo("MODIFIEDDATE", "MODIFIEDBY", $E.staff.id);

			const changed = this.getChangedProperties();
			if (changed.length > 0) {
				for (let i = 0; i < changed.length; i++) {
					let key = changed[i];
					bd.setValue(key, this.getValue(key), this.getType(key));
				}
			}

			$F.dataService("SystemDo5", {
				async: !!isSync,
				data: {
					token: proj.token,
					dbPool: '',
					xml: bd.getData()
				},
				digest: proj.digest,
				success: function(data) {
					if (data.code < 1) {
						$F.log('Customer - save', $F.lang('customer.savefail'));
						return $F.alert($F.lang('customer.savefail') + " : " + data.message);
					}
					var ALWCSS = proj.getParam("ALWCSS");
					if (ALWCSS == "0") {
						//instance
					} else {
						$F.log('Customer - save', $F.lang('customer.savesuccess'));
					}
					if (successCallback) {
						successCallback(tempCustomerGuid);
					}
				},
				fail: function(jqXHR, textStatus, errorThrown) {
					if (failCallback) {
						failCallback();
					} else {
						$F.log('Customer - save', $F.lang('customer.savefail'));
						$F.alert($F.lang('customer.savefail') + " : " + errorThrown.message);
					}
				},
				always : function() {
					alwaysCallback && alwaysCallback();
				}
			});

			this.saveHistory();
		},

		/**
		 * 清空所有属性
		 */
		clear : function() {
			for (var p in this.values) {
				this.values[p] = "";
				this.originalValues[p] = "";
			}
		},

		clone : function() {
			const cc = new Customer(this.project, this.fields, this.dbPool);
			for (let p in this.values) {
				cc.setPropertyByName(p, this.values[p]);
				cc.setOriginalPropertyByName(p, this.originalValues[p]);
			}
			return cc;
		},

		getValue : function(propertyName) {
			return this.getProperty(propertyName);
		},

		setValue : function(propertyName, propertyValue) {
			this.setPropertyByName(propertyName, propertyValue);
			if (this === this.project.customer) {
				this.project.events.notify($CONST.ModuleEvent.ECM_CUSTOMERPROPERTIESCHANGED, {
					field: propertyName,
					newValue: propertyValue
				});
			}
		},
		getProperty : function(propertyName) {
			return this.values[propertyName.toLowerCase()];
		},
		setPropertyByName : function(propertyName, propertyValue) {
			this.values[propertyName.toLowerCase()] = propertyValue;
		},
		getOriginalPropertyByName : function(propertyName) {
			return this.originalValues[propertyName.toLowerCase()];
		},
		setOriginalPropertyByName : function(propertyName, propertyValue) {
			this.originalValues[propertyName.toLowerCase()] = propertyValue;
		},
		getType: function(propertyName) {
			return this.fields[propertyName.toLowerCase()].type;
		},

		prettyPrint : function() {
			var fields = this.project.customerFieldsCache.fields;
			for (var i = 0, j = fields.length; i < j; i++) {
				$F.log("Customer.prettyPrint", fields[i] + " : " + this.values[fields[i]]);
			}
		},

		bean : function() {
			var bean = {}, fields = this.project.customerFieldsCache.fields;
			for (var i = 0, j = fields.length; i < j; i++) {
				bean[fields[i]] = this.values[fields[i]];
			}
		},

		generateByGuid : function(customerGuid) {
			const c = this,
				proj = this.project;
			if ($F.isNull(customerGuid) || $.trim(customerGuid) == "") {
				$F.log("Customer.generateByGuid", "空的客户GUID");
			} else {
				var sqlKey = "ECore.Customer.searchByGuid";
				$F.dataService('SystemDo2', {
					data : $F.sqlbean2(sqlKey, proj.token, this.dbPool, [ $E.staff.epidSql, customerGuid ]),
					async : false,
					digest: proj.digest,
					success : function(data) {
						if (data.code < 1) {
							$F.log("Customer.generateByGuid", "Search customer failed.");
						}
						// Fixed by kevin, count can't be zero
						if (data.value[0].count > 0) {
							var custFields = data.value[0].fields[0]
							for (var i = 0, j = custFields.length; i < j; i++) {
								c.setOriginalPropertyByName(proj.customerFieldsCache.fields[i], custFields[i]);
								c.setPropertyByName(proj.customerFieldsCache.fields[i], custFields[i]);
							}
							$F.log('Customer - generateByGuid', '客户加载完毕：' + customerGuid);
						} else {
							$F.err("Customer - generateByGuid", "客户不存在：" + customerGuid);
						}
					},
					fail : function() {
						$F.log("Customer - generateByGuid", "Search customer ajax failed.");
					}
				});
			}
			return c;
		},

		getChangedProperties : function() {
			var changedProperties = [],
				fields = this.project.customerFieldsCache.fields;
			for (var i = 0, j = fields.length; i < j; i++) {
				var field = fields[i];
				var fieldVal = this.getProperty(field);
				if (!$F.isNull(fieldVal)) {
					if (field.toUpperCase() !== "CUSTOMER_GUID") {
						if (this.getOriginalPropertyByName(field) !== fieldVal) { //与原始customer对象数据不同时候，才需要更新
							changedProperties.push(field);
						}
					}
				}
			}
			return changedProperties;
		},

		autoSaveCustomer : function() {
			const proj = this.project;
			$F.log('Customer - autoSaveCustomer', "Auto save current customer.");
			var tempCustomerGuid = this.getValue('customer_guid');
			if (!$F.isEmpty(tempCustomerGuid) && tempCustomerGuid.trim() === Customer.anonymousGuid.trim()) {
				var tempCustomerName = this.getProperty("customername");
				if (tempCustomerName !== "匿名客户" && tempCustomerName !== "anonymous") {
					tempCustomerGuid = Guid.raw();
				} else {
					return $F.log('Customer - autoSaveCustomer', '匿名客户不做自动保存');
				}
			}
			const changed = this.getChangedProperties();
			if (changed.length > 0) {
				const bd = new BoundData("Customer" + $E.staff.epidSql);
				bd.setKey('customer_guid');
				bd.setValue('customer_guid', tempCustomerGuid);
				bd.setCreateInfo("CREATEDDATE", "CREATEDBY", $E.staff.id);
				bd.setModifyInfo("MODIFIEDDATE", "MODIFIEDBY", $E.staff.id);
				for (let i = 0; i < changed.length; i++) {
					let key = changed[i];
					bd.setValue(key, this.getValue(key), this.getType(key));
				}
				$F.ajaxSync("SystemDo5", {
					token : proj.token,
					dbPool : this.dbPool,
					xml : bd.getData()
				}, proj.digest);

				this.saveHistory();
			}
		},

		saveHistory : function() {
			const proj = this.project,
				fields = proj.customerFieldsCache.fields;
			if (proj.getParam("CUSHIS") == 1) {
				const bd = new BoundData("customer_his" + $E.staff.epidSql);
				bd.setKey('customerhis_guid');
				bd.setValue('customerhis_guid', Guid.raw());
				bd.setValue('customer_guid', proj.customer.getValue('customer_guid'));
				const cpArr = this.getChangedProperties();
				bd.setValue('modifycolumn', cpArr.join(','));
				for (let i = 0; i < fields.length; i++) {
					let key = fields[i];
					bd.setValue(key, proj.customer.getValue(key), proj.customer.getType(key));
				}
				bd.setModifyInfo("modifydate", "modifyby", $E.staff.id);
				const ret = $F.ajaxSync("SystemDo5", {
					token : proj.token,
					dbPool : '',
					xml : bd.getData()
				}, proj.digest);
				if (ret && ret.code === 1) {
					$F.log('Customer - saveHistory', 'Save history successful');
				} else {
					$F.log('Customer - saveHistory', 'Save history failed');
				}
			}
		},

		generateBoundDataByGuid : function(customerGuid) {
			var custBoundData = null,
				fields = this.project.customerFieldsCache.fields;
			if ($F.isNull(customerGuid) || $.trim(customerGuid) === "") {
				$F.log("Customer.generateByGuid", "customer_guid is empty");
			} else {
				var sqlKey = "ECore.Customer.searchByGuid";
				$F.dataService('SystemDo2', {
					data : $F.sqlbean2(sqlKey, this.project.token, this.dbPool, [ $E.staff.epidSql, customerGuid ]),
					async : false,
					digest: this.project.digest,
					success : function(data) {
						if (data.code < 1) {
							$F.log("Customer.generateByGuid", "Search customer failed.");
						}
						if (data.value[0].count >= 0) {
							custBoundData = new BoundData("customer");
							custBoundData.setKey("customer_guid");
							custBoundData.setCreateInfo("CREATEDDATE", "CREATEDBY", $E.staff.id);
							custBoundData.setModifyInfo("MODIFIEDDATE", "MODIFIEDBY", $E.staff.id);

							var custFields = data.value[0].fields[0];
							for (var i = 0, j = custFields.length; i < j; i++) {
								custBoundData.setValue(fields[i], custFields[i], this.getType(fields[i]));
							}
						} else {
							$F.log("Customer.generateByGuid", "Not found customer by guid " + customerGuid);
						}
					},
					fail : function() {
						$F.log("Customer.generateByGuid", "Search customer ajax failed.");
					}
				});
			}
			return custBoundData;
		}
	};

	return {
		encFields: Customer.encFields,
		create : function(project, dbPool) {
			let customerFields = project.getCache('CUSTOMER_FIELDS');
			if (! customerFields) {
				customerFields = {};
				const sqls = ["customer" + $E.staff.epidSql];
				// 加载objective字段列表
				$F.dataService('SystemDo3', {
					data : {
						token: project.token,
						dbPool: dbPool,
						sqls: sqls
					},
					silent: true,
					async : false,
					digest: project.digest,
					success : function(data) {
						if (data.code > 0) {
							const columns = data.value[0].columns;
							for (let i=0; i<columns.length; i++) {
								customerFields[columns[i][0].toLowerCase()] = {
									length : columns[i][3],
									type : $PublicFun.fieldTypeStringToBoundType(columns[i][2])
								}
							}
							project.putCache('CUSTOMER_FIELDS', customerFields);
						} else {
							$F.err('Customer - create', data.message);
						}
					}
				})
			}
			return new Customer(project, customerFields, dbPool);
		},

		getAnonymousGuid : function() {
			return Customer.anonymousGuid;
		},

		createByGuid : function(project, customerGuid, dbPool) {
			let customerFields = project.getCache('CUSTOMER_FIELDS')
			const cust = new Customer(project, customerFields, dbPool);
			cust.generateByGuid(customerGuid);
			return cust;
		},

		checkExists : function(project, sqlKey, params) {
			var ret = undefined;
			if (params) {
				$F.dataService('SystemDo2', {
					data : $F.sqlbean(sqlKey, project.token, params),
					async : false,
					digest: project.digest,
					success : function(data) {
						if (data.code >= 1 && data.value[0].count >= 0) {
							ret = data.value[0].fields[0][0];
						}
					}
				});
			}
			return ret;
		},

		createNewCustomerForPDS : function(customerGuid, phoneNumber) {
			if ($F.isEmpty(customerGuid)) {
				customerGuid = Guid.raw();
			}
			var mobile = "";
			var tel_1 = "";
			if (Verify.isMobile(phoneNumber)) {
				mobile = phoneNumber;
			} else {
				tel_1 = phoneNumber;
			}
			var r = $F.sqlbean(sqlKey, this.project.token, [ $E.staff.epidSql, "customer_guid,customername,tel_1,mobile,createddate,createdby", customerGuid + "','','" + tel_1 + "','" + mobile + "','" + $F.getDbTime() + "','" + $E.staff.id ]);
			var sqlKey = "ECore.Customer.insert";
			$F.dataService('SystemDo1', {
				data : r,
				async : false,
				digest: this.project.digest,
				success : function(data) {
					if (data.code < 1) {
						//insert failed
					}
				}
			});
			return customerGuid;
		}
	};
});
